package io.light.frame.dal.mybatis.generator.core.context;

import io.light.frame.dal.mybatis.generator.core.cfg.ModuleConfiguration;
import io.light.frame.dal.mybatis.generator.core.domain.DesignXml;
import io.light.frame.dal.mybatis.generator.core.domain.Generation;
import io.light.frame.dal.mybatis.generator.core.domain.clazz.Clazz;
import io.light.frame.dal.mybatis.generator.core.domain.mapper.Mapper;
import io.light.frame.dal.mybatis.generator.core.exceptions.MybatisGenException;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Generation context
 *
 * @author Ivan
 * @version 1.0.0
 * @date 2021-06-12 14:55
 */
@Getter
@Setter
public class GenerationContext {
    private static final ThreadLocal<GenerationContext> CTX = new ThreadLocal<>();
    public static final String VAR_KEY_CREATED_FILES = "VAR_KEY_CREATED_FILES";
    private final ModuleConfiguration config;
    private final String module;
    private final File projectDir;
    private final Mapper mapper;
    private final DesignXml designXml;
    private final transient Map<String, Object> vars = new HashMap<>();
    private final GenResult result;

    private GenerationContext(Generation generation, Mapper mapper, DesignXml designXml) {
        this.module = generation.getModuleName();
        this.projectDir = generation.getProjectDir();
        this.config = generation.getConfig();
        this.mapper = mapper;
        this.designXml = designXml;
        this.result = new GenResult();
        this.result.setDetail(GenResult.Detail.from(this));
    }

    public static GenerationContext create(Generation generation, Mapper mapper, DesignXml designXml) {
        if (CTX.get() != null) {
            throw new MybatisGenException("The current thread generator context already exists");
        }
        CTX.set(new GenerationContext(generation, mapper, designXml));
        return CTX.get();
    }

    public static GenerationContext current() {
        return current(true);
    }

    public static GenerationContext current(boolean check) {
        if (check && CTX.get() == null) {
            throw new MybatisGenException("The current thread generator context has not initialized");
        }
        return CTX.get();
    }

    public static void addErr(Exception err) {
        current().getResult().addErr(err);
    }

    public static void addCreatedFile(File file) {
        addCreatedFile(file, false);
    }

    @SuppressWarnings("unchecked")
    public static void addCreatedFile(File file, boolean force) {
        GenerationContext context = current(false);
        if (context == null) {
            return;
        }
        if (!force && file.exists()) {
            return;
        }
        List<File> files = (List<File>) context.getVars().computeIfAbsent(VAR_KEY_CREATED_FILES,
                k -> new ArrayList<>());
        files.add(file);
    }

    public static Clazz entityClazz() {
        return current().getMapper().getEntityClazz();
    }

    public static GenResult result() {
        return current().getResult();
    }

    @SuppressWarnings("ALL")
    public static void destroy() {
        GenerationContext context = current(false);
        if (context == null) {
            return;
        }
        if (!context.getResult().isSuccess()) {
            List<File> files = (List<File>) context.getVars().computeIfAbsent(VAR_KEY_CREATED_FILES, k -> null);
            if (!CollectionUtils.isEmpty(files)) {
                files.forEach(File::delete);
            }
        }
        context.clean();
        CTX.remove();
    }

    private void clean() {
        vars.clear();
    }
}
